home *** CD-ROM | disk | FTP | other *** search
/ Visual Cafe 3 / Visual Cafe 3.ISO / Vcafe / JFC.bin / KeyStroke.java < prev    next >
Text File  |  1998-06-30  |  16KB  |  404 lines

  1. /*
  2.  * @(#)KeyStroke.java    1.20 98/03/12
  3.  * 
  4.  * Copyright (c) 1997 Sun Microsystems, Inc. All Rights Reserved.
  5.  * 
  6.  * This software is the confidential and proprietary information of Sun
  7.  * Microsystems, Inc. ("Confidential Information").  You shall not
  8.  * disclose such Confidential Information and shall use it only in
  9.  * accordance with the terms of the license agreement you entered into
  10.  * with Sun.
  11.  * 
  12.  * SUN MAKES NO REPRESENTATIONS OR WARRANTIES ABOUT THE SUITABILITY OF THE
  13.  * SOFTWARE, EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE
  14.  * IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
  15.  * PURPOSE, OR NON-INFRINGEMENT. SUN SHALL NOT BE LIABLE FOR ANY DAMAGES
  16.  * SUFFERED BY LICENSEE AS A RESULT OF USING, MODIFYING OR DISTRIBUTING
  17.  * THIS SOFTWARE OR ITS DERIVATIVES.
  18.  * 
  19.  */
  20. package com.sun.java.swing;
  21.  
  22. import java.awt.event.KeyEvent;
  23. import java.awt.event.InputEvent;
  24. import java.util.Hashtable;
  25. import java.io.Serializable;
  26.  
  27. /**
  28.  * A KeyStroke instance represents a key being typed on the keyboard -- it
  29.  * contains both a char code for the key and a modifier (alt, shift, ctrl, 
  30.  * meta, or a combination). 
  31.  * <p>
  32.  * KeyStroke objects are used to define high-level (semantic) action events.
  33.  * Instead of trapping every keystroke and throwing away the ones you are
  34.  * not interested in, those keystrokes you care about automatically initiate
  35.  * actions on the components they are registered with. 
  36.  * <p>
  37.  * KeyStroke objects handle both character-code generating keystrokes you 
  38.  * would trap with a KeyTyped event handler and key-code generating keystrokes
  39.  * (like Enter or F1) that you would trap with a KeyPressed event handler.
  40.  * <p>
  41.  * KeyStroke objects are immutable and unique.
  42.  * <p>
  43.  * All KeyStroke objects are cached. To get one, use <code>getKeyStroke</code>.
  44.  * <p>
  45.  * Warning: serialized objects of this class will not be compatible with
  46.  * future swing releases.  The current serialization support is appropriate 
  47.  * for short term storage or RMI between Swing1.0 applications.  It will
  48.  * not be possible to load serialized Swing1.0 objects with future releases
  49.  * of Swing.  The JDK1.2 release of Swing will be the compatibility
  50.  * baseline for the serialized form of Swing objects.
  51.  *
  52.  * @see JComponent#registerKeyboardAction
  53.  * @see #getKeyStroke
  54.  *
  55.  * @version 1.20 03/12/98
  56.  * @author Arnaud Weber
  57.  */
  58. public class KeyStroke implements Serializable {
  59.     private static final Object pressedCharCacheKey = 
  60.         new StringBuffer("KeyStroke.pressedCharCacheKey");
  61.     private static final Object releasedCharCacheKey = 
  62.         new StringBuffer("KeyStroke.releasedCharCacheKey");
  63.     private static final Object pressedCodeCacheKey = 
  64.         new StringBuffer("KeyStroke.pressedCodeCacheKey");
  65.     private static final Object releasedCodeCacheKey = 
  66.         new StringBuffer("KeyStroke.releasedCodeCacheKey");
  67.  
  68.     char keyChar;
  69.     int  keyCode;
  70.     int  modifiers;
  71.     boolean onKeyRelease;
  72.  
  73.     /* We cache 114 key stroke with keyChar (1368 bytes) */
  74.     /* We cache 114 * 8 key stroke with keyCode and popular modifiers (10944 bytes) */ 
  75.     /* Total cache is around 11K */
  76.  
  77.     static final int MIN_ASCII_CACHE_INDEX = '\n'; 
  78.     static final int MAX_ASCII_CACHE_INDEX = 0x7F;
  79.     /* It is impossible to instantiate a KeyStroke. Use getKeyStroke() instead **/
  80.     private KeyStroke() {
  81.         
  82.     }
  83.  
  84.     static KeyStroke getCachedKeyCharKeyStroke(char keyChar,boolean onKeyRelease) {
  85.         KeyStroke result = null;
  86.         if(keyChar >= MIN_ASCII_CACHE_INDEX && keyChar < MAX_ASCII_CACHE_INDEX) {
  87.             synchronized(KeyStroke.class) {
  88.                 KeyStroke cache[];
  89.                 if(onKeyRelease) 
  90.                     cache = (KeyStroke[])SwingUtilities.appContextGet(
  91.                         releasedCharCacheKey);
  92.                 else
  93.                     cache = (KeyStroke[])SwingUtilities.appContextGet(
  94.                         pressedCharCacheKey);
  95.                 if(cache != null)
  96.                     result = cache[((int)keyChar) - MIN_ASCII_CACHE_INDEX];
  97.             }
  98.         }
  99.         return result;
  100.     }
  101.  
  102.     static void cacheKeyCharKeyStroke(KeyStroke ks,boolean onKeyRelease) {
  103.         if(ks.keyChar >= MIN_ASCII_CACHE_INDEX && ks.keyChar < MAX_ASCII_CACHE_INDEX) {
  104.             synchronized(KeyStroke.class) {
  105.                 if(onKeyRelease) {
  106.                     KeyStroke releasedKeyCharKeyStrokeCache[] = (KeyStroke[])
  107.                         SwingUtilities.appContextGet(releasedCharCacheKey);
  108.                     if(releasedKeyCharKeyStrokeCache == null) {
  109.                         releasedKeyCharKeyStrokeCache = new KeyStroke[MAX_ASCII_CACHE_INDEX - MIN_ASCII_CACHE_INDEX];
  110.                         SwingUtilities.appContextPut(
  111.                             releasedCharCacheKey, releasedKeyCharKeyStrokeCache);
  112.                     }
  113.                     releasedKeyCharKeyStrokeCache[((int)ks.keyChar) - MIN_ASCII_CACHE_INDEX] = ks;
  114.                 } else {
  115.                     KeyStroke pressedKeyCharKeyStrokeCache[] = (KeyStroke[])
  116.                         SwingUtilities.appContextGet(pressedCharCacheKey);
  117.                     if(pressedKeyCharKeyStrokeCache == null) {
  118.                         pressedKeyCharKeyStrokeCache = new KeyStroke[MAX_ASCII_CACHE_INDEX - MIN_ASCII_CACHE_INDEX];
  119.                         SwingUtilities.appContextPut(
  120.                             pressedCharCacheKey, pressedKeyCharKeyStrokeCache);
  121.                     }
  122.                     pressedKeyCharKeyStrokeCache[((int)ks.keyChar) - MIN_ASCII_CACHE_INDEX] = ks;
  123.                 }
  124.             }
  125.         }
  126.     }
  127.  
  128.     static int subIndexForModifier(int modifiers) {
  129.         if(modifiers == 0)
  130.             return 0;
  131.         else if(modifiers == InputEvent.SHIFT_MASK)
  132.             return 1;
  133.         else if(modifiers == InputEvent.CTRL_MASK)
  134.             return 2;
  135.         else if(modifiers == InputEvent.ALT_MASK)
  136.             return 3;
  137.         
  138.         return -1;
  139.     }
  140.  
  141.     static KeyStroke getCachedKeyStroke(int keyCode,int modifiers,boolean onKeyRelease) {
  142.         int subIndex;
  143.         KeyStroke result = null;
  144.         if(keyCode >= MIN_ASCII_CACHE_INDEX && keyCode < MAX_ASCII_CACHE_INDEX &&
  145.            (subIndex = subIndexForModifier(modifiers)) != -1) {
  146.             synchronized(KeyStroke.class) {
  147.                 KeyStroke cache[][];
  148.                 if(onKeyRelease) 
  149.                     cache = (KeyStroke[][])SwingUtilities.appContextGet(
  150.                         pressedCodeCacheKey);
  151.                 else
  152.                     cache = (KeyStroke[][])SwingUtilities.appContextGet(
  153.                         releasedCodeCacheKey);
  154.  
  155.                 if(cache != null)
  156.                     result = cache[subIndex][keyCode - MIN_ASCII_CACHE_INDEX];
  157.             }
  158.         }
  159.         return result;
  160.     }
  161.  
  162.     static void cacheKeyStroke(KeyStroke ks) {
  163.         int subIndex = -1;
  164.         if(ks.keyCode >= MIN_ASCII_CACHE_INDEX && ks.keyCode < MAX_ASCII_CACHE_INDEX &&
  165.            (subIndex = subIndexForModifier(ks.modifiers)) != -1) {
  166.             synchronized(KeyStroke.class) {
  167.                 KeyStroke cache[][] = null;
  168.                 if(ks.onKeyRelease) {
  169.                     KeyStroke[][] pressedKeyCodeKeyStrokeCache = (KeyStroke[][])
  170.                         SwingUtilities.appContextGet(pressedCodeCacheKey);
  171.                     if(pressedKeyCodeKeyStrokeCache == null) {
  172.                         pressedKeyCodeKeyStrokeCache = new KeyStroke[4][MAX_ASCII_CACHE_INDEX - 
  173.                                                                          MIN_ASCII_CACHE_INDEX];
  174.                         SwingUtilities.appContextPut(
  175.                             pressedCodeCacheKey, pressedKeyCodeKeyStrokeCache);
  176.                     }
  177.                     cache = pressedKeyCodeKeyStrokeCache;
  178.                 } else {
  179.                     KeyStroke[][] releasedKeyCodeKeyStrokeCache = (KeyStroke[][])
  180.                         SwingUtilities.appContextGet(releasedCodeCacheKey);
  181.                     if(releasedKeyCodeKeyStrokeCache == null) {
  182.                         releasedKeyCodeKeyStrokeCache = new KeyStroke[4][MAX_ASCII_CACHE_INDEX - 
  183.                                                                           MIN_ASCII_CACHE_INDEX];
  184.                         SwingUtilities.appContextPut(
  185.                             releasedCodeCacheKey, releasedKeyCodeKeyStrokeCache);
  186.                     }
  187.                     cache = releasedKeyCodeKeyStrokeCache;
  188.                 }
  189.  
  190.                 cache[subIndex][ks.keyCode - MIN_ASCII_CACHE_INDEX] = ks;
  191.             }
  192.         }
  193.     }
  194.     
  195.     /**
  196.      * Return a shared instance of a key stroke that is
  197.      * activated when the key is pressed.
  198.      *
  199.      * @param keyChar the character value for a keyboard key
  200.      * @return a KeyStroke object for that key
  201.      */
  202.     public static KeyStroke getKeyStroke(char keyChar) {
  203.         return getKeyStroke(keyChar,false);
  204.     }
  205.  
  206.     /**
  207.      * Return a shared instance of a key stroke, specifying
  208.      * whether the key is considered to be activated when it is 
  209.      * pressed or when it is released.
  210.      *
  211.      * @param keyChar the character value for a keyboard key
  212.      * @param onKeyRelease a boolean value. When true, specifies that
  213.      *        the key is active when it is released.
  214.      * @return a KeyStroke object for that key
  215.      */
  216.     public static KeyStroke getKeyStroke(char keyChar,boolean onKeyRelease) {
  217.         KeyStroke result = getCachedKeyCharKeyStroke(keyChar,onKeyRelease);
  218.  
  219.         if(result == null) {
  220.             result = new KeyStroke();
  221.             result.keyChar = keyChar;
  222.             result.modifiers = 0;
  223.             result.onKeyRelease = onKeyRelease;
  224.             cacheKeyCharKeyStroke(result,onKeyRelease);
  225.         }
  226.         return result;
  227.     }
  228.  
  229.     /**
  230.      * Return a shared instance of a key stroke given a char code and a set
  231.      * of modifiers, specifying whether the key is activated when it is pressed
  232.      * or released.
  233.      * <p>
  234.      * The "virtual key" constants defined in java.awt.event.KeyEvent can be 
  235.      * used to specify the key code. For example:<ul>
  236.      * <li>java.awt.event.KeyEvent.VK_ENTER 
  237.      * <li>java.awt.event.KeyEvent.VK_TAB
  238.      * <li>java.awt.event.KeyEvent.VK_SPACE
  239.      * </ul>
  240.      * The modifiers consist of any combination of:<ul>
  241.      * <li>java.awt.Event.SHIFT_MASK (1)
  242.      * <li>java.awt.Event.CTRL_MASK (2)
  243.      * <li>java.awt.Event.META_MASK (4)
  244.      * <li>java.awt.Event.ALT_MASK (8)
  245.      * </ul>
  246.      * Since these numbers are all different powers of two, any combination of
  247.      * them is an integer in which each bit represents a different
  248.      * modifier key.
  249.      *
  250.      * @param keyCode an int specifying the numeric code for a keyboard key
  251.      * @param modifiers an int specifying any combination of the key modifiers.
  252.      * @param onKeyRelease a boolean value. When true, specifies that
  253.      *        the key is active when it is released.
  254.      * @return a KeyStroke object for that key
  255.      *
  256.      * @see java.awt.event.KeyEvent
  257.      * @see java.awt.Event
  258.      */
  259.     public static KeyStroke getKeyStroke(int keyCode,int modifiers,boolean onKeyRelease) {
  260.         KeyStroke result = getCachedKeyStroke(keyCode,modifiers,onKeyRelease);
  261.  
  262.         if(result == null) {
  263.             result = new KeyStroke();
  264.             result.keyCode = keyCode;
  265.             result.modifiers = modifiers;
  266.             result.onKeyRelease = onKeyRelease;
  267.             cacheKeyStroke(result);
  268.         }
  269.  
  270.         return result;
  271.     }
  272.  
  273.     /**
  274.      * Return a shared instance of a key stroke given a char code and a set
  275.      * of modifiers -- the key is activated when it is pressed.
  276.      * <p>
  277.      * The modifiers consist of any combination of:<ul>
  278.      * <li>java.awt.Event.SHIFT_MASK (1)
  279.      * <li>java.awt.Event.CTRL_MASK (2)
  280.      * <li>java.awt.Event.META_MASK (4)
  281.      * <li>java.awt.Event.ALT_MASK (8)
  282.      * </ul>
  283.      * Since these numbers are all different powers of two, any combination of
  284.      * them is an integer in which each bit represents a different
  285.      * modifier key.
  286.      *
  287.      * @param keyChar the character value for a keyboard key
  288.      * @param modifiers an int specifying any combination of the key modifiers.
  289.      * @return a KeyStroke object for that key
  290.      */
  291.     public static KeyStroke getKeyStroke(int keyCode,int modifiers) {
  292.         return getKeyStroke(keyCode,modifiers,false);
  293.     }
  294.  
  295.     /**
  296.      * Return a keystroke from an event.
  297.      * <p>
  298.      * This method obtains the keyChar from a KeyTyped event,
  299.      * and the keyCode from a KeyPressed or KeyReleased event,
  300.      * so you don't have to.
  301.      *
  302.      * @param anEvent the KeyEvent to obtain the KeyStroke from
  303.      * @return the KeyStroke that precipitated the event
  304.      */
  305.     public static KeyStroke getKeyStrokeForEvent(KeyEvent anEvent) {
  306.         KeyStroke ks = null;
  307.         switch(anEvent.getID()) {
  308.         case KeyEvent.KEY_PRESSED:
  309.             ks = getKeyStroke(anEvent.getKeyCode(),anEvent.getModifiers(),false);
  310.             break;
  311.         case KeyEvent.KEY_RELEASED:
  312.             ks = getKeyStroke(anEvent.getKeyCode(),anEvent.getModifiers(),true);
  313.             break;
  314.         case KeyEvent.KEY_TYPED:
  315.             ks = getKeyStroke(anEvent.getKeyChar());
  316.             break;
  317.         }
  318.         return ks;
  319.     }
  320.  
  321.     /**
  322.      * Return a shared instance of a key stroke matching a string
  323.      * representation.
  324.      *
  325.      * @param representation a String specifying a KeyStroke
  326.      * @return a KeyStroke object matching the specification. 
  327.      */
  328.     public static KeyStroke getKeyStroke(String representation) {
  329.         // Not implemented
  330.         return null;
  331.     }
  332.  
  333.     /**
  334.      *
  335.      */
  336.     public char getKeyChar() { return keyChar; }
  337.     /**
  338.      *
  339.      */
  340.     public int  getKeyCode() { return keyCode; }
  341.     /**
  342.      *
  343.      */
  344.     public int getModifiers() { return modifiers; }
  345.     /**
  346.      *
  347.      */
  348.     public boolean isOnKeyRelease() { return onKeyRelease; }
  349.  
  350.     private static String getStringRepresentation(char keyChar,int modifiers,boolean kr) {
  351.         return "keyChar " + KeyEvent.getKeyModifiersText(modifiers) + keyChar +  
  352.             (kr?"-R":"-P");
  353.     }
  354.  
  355.     private static String getStringRepresentation(int keyCode,int modifiers,boolean kr) {
  356.         return "keyCode " + KeyEvent.getKeyModifiersText(modifiers) + KeyEvent.getKeyText(keyCode) +
  357.             (kr?"-R":"-P");
  358.     }
  359.  
  360.     /**
  361.      * Returns a numeric value for this object that is likely to be
  362.      * reasonably unique, so it can be used as the index value in a
  363.      * Hashtable.
  364.      *
  365.      * @return an int that "represents" this object
  366.      * @see java.util.Hashtable
  367.      */
  368.     public int hashCode() {
  369.         return (((int) keyChar) + 1) * (2 * (keyCode + 1)) * (modifiers+1) +
  370.             (onKeyRelease ? 1 : 2);
  371.     }
  372.  
  373.     /**
  374.      * Returns true if this object is identical to the specified object.
  375.      *
  376.      * @param anObject the Object to compare this object to
  377.      * @return true if the objects are identical
  378.      */
  379.     public boolean equals(Object anObject) {
  380.         if(anObject instanceof KeyStroke) {
  381.             KeyStroke ks = (KeyStroke) anObject;
  382.             if(ks.keyChar == keyChar && ks.keyCode == keyCode && 
  383.                ks.onKeyRelease == onKeyRelease && ks.modifiers == modifiers)
  384.                 return true;
  385.         }
  386.         return false;
  387.     }
  388.  
  389.     /**
  390.      * Returns a string that displays and identifies this
  391.      * object's properties.
  392.      *
  393.      * @return a String representation of this object
  394.      */
  395.     public String toString() {
  396.         if(keyChar == 0)
  397.             return getStringRepresentation(keyCode,modifiers,onKeyRelease);
  398.         else
  399.             return getStringRepresentation(keyChar,0,onKeyRelease);
  400.     }
  401. }
  402.  
  403.  
  404.